/****************************************************************************
 * (c) 2001 StreamBox Inc.  http://www.streambox.com/ 
 *
 * Division: Moscow Research Division
 * Project:  Tidy Scaling (video compression project)
 *
 * Contents: Filter-based scaling functions. Only ^2 scaling factor allowed.
 *           File contains 8-item fast filter implemntation.
 *
 * History:  13-Sep-2001 - Created by Smirnov K
 *           14-Sep-2001 - fixed bugs with bounds
 *			 18-Sep-2001 adedd ScaleCnannelDownX2Vrtical/Horisontal, fixed bugs in _asm
 *			 25-Sep-02-Oct 2001 removed files with MMX to scale_msk_f8_mmx.c, changed 
 *								calls params, changed represetation of functions to more readable
 ****************************************************************************/
/**
 * \file scale_msk_f8.c
 *  File contains 8-item fast filter implemntation. 
 *  Filter coeficients {-4 -9 19 58 58 19 -9 -4}
 *  Functions:
 *  void ScaleChannelUpX2Filter8_2Vertical() 
 *  void ScaleChannelUpX2Filter8_2Horisontal()
 *  void ScaleChannelDownX2Filter8_2Vertical()
 *  void ScaleChannelDownX2Filter8_2Horisontal()
 */ 

#include "Scale_msk.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*============================= ScaleChannelUpX2Filter8_2Vertical ==============================*/
/**
 * Scale UP Vertical Dimension of 2D channel. Functon returns image sizes (w)x(2h) 
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height
 * \retval - none
 */
void ScaleChannelUpX2Filter8_2Vertical(BYTE* in, BYTE* out, int w, int h)
{
	int w_in = w, h_in = h, w_out = w_in, h_out = h_in<<1, h_end = h_in-3;
    
	int i, j ,c0,c1,c2,c3;
	BYTE* pIn, *pOut;

	pIn = in;
	pOut = out;

		for (i= 0; i<w_in; i++)
		{
			c0=pIn[i       ];
			c1=pIn[i+w_in  ];
			c2=pIn[i+w_in*2];
			pOut[i      ]=	CLIP_F( (58*c0 + 19*c1 - 4*c2 + 36)/73 );
			pOut[i+w_out]=	CLIP_F( (19*c0 + 58*c1 - 9*c2 + 34)/68 );
		}


	for (j = 0; j<h_end; j++)
	{
	
	pIn  += w_in;
	pOut += w_out*2;

		for(i=0; i<w_in; i++) 
		{
			c0=pIn[i-w_in  ];
			c1=pIn[i       ];
			c2=pIn[i+w_in  ];
			c3=pIn[i+w_in*2];
			pOut[i      ]= CLIP_F( (-9*c0 + 58*c1 + 19*c2 -4*c3 + 32)>>6 );
			pOut[i+w_out]= CLIP_F( (-4*c0 + 19*c1 + 58*c2 -9*c3 + 32)>>6 );
		}
	}

	pIn  += w_in;
	pOut += w_out*3;

		for (i=0; i<w_in; i++)
		{
			c0=pIn[i-w_in];
			c1=pIn[i];
			c2=pIn[i+w_in];
//		    c3=pIn[i+w_in*2]; // does not exist
			pOut[i-w_out  ]=CLIP_F( (-9*c0 + 58*c1 + 19*c2 -4*c2 + 32)>>6 ); 
			pOut[i        ]=CLIP_F( (-4*c0 + 19*c1 + 58*c2 -9*c2 + 32)>>6 );
			pOut[i+w_out  ]=CLIP_F( (-9*c1 + 58*c2 + 19*c2 + 34)/68 );
			pOut[i+w_out*2]=CLIP_F( (-4*c1 + 19*c2 + 58*c2 + 36)/73 );
		}
}


/*============================= ScaleChannelUpX2Filter8_2Horisontal ==============================*/
/**
 * Scale UP Horisontal Dimension of 2D channel.The Functon returns image sizes (2w)x(h)
 *
 * \param in          [IN]  - pointer to input 2D channel
 * \param out         [OUT] - pointer to output 2D channel
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height
 * \retval - none
 */

void ScaleChannelUpX2Filter8_2Horisontal(BYTE * in, BYTE * out, int w,int h)
{
	int w_in = w, h_in = h, w_out = w<<1, h_out = h_in, w_end = w_in-3;
  	int i, j;
    int c0,c1,c2;
	BYTE *pIn, *pOut;

    for(i=0; i<h_in; i++)
    {
		pIn = in+i*w_in;
		pOut = out+i*w_out;

			c0=pIn[0];
			c1=pIn[1];
			c2=pIn[2];
			pOut[0]=	CLIP_F( (58*c0 + 19*c1 - 4*c2 + 36)/73 );
			pOut[1]=	CLIP_F( (19*c0 + 58*c1 - 9*c2 + 34)/68 );

		pOut +=2;

        for(j = 0; j<w_end; j++, pIn++, pOut+=2) 
        {
			pOut[0]= CLIP_F( (-9*pIn[0] + 58*pIn[1] + 19*pIn[2] -4*pIn[3] + 32)>>6 );
			pOut[1]= CLIP_F( (-4*pIn[0] + 19*pIn[1] + 58*pIn[2] -9*pIn[3] + 32)>>6 );
        }
         
			c0=pIn[0];
			c1=pIn[1];
			c2=pIn[2];
//		    c3=pIn[i+w_in*2]; // does not exist
			pOut[0]=CLIP_F( (-9*c0 + 58*c1 + 19*c2 - 4*c2 + 32)>>6 ); 
			pOut[1]=CLIP_F( (-4*c0 + 19*c1 + 58*c2 - 9*c2 + 32)>>6 );
			pOut[2]=CLIP_F( (-9*c1 + 58*c2 + 19*c2 + 34)/68 );
			pOut[3]=CLIP_F( (-4*c1 + 19*c2 + 58*c2 + 36)/73 );
	}
}


/*============================= ScaleChannelDownX2Filter8_2Vertical ==============================*/
/**
 * Scale DOWN Vertical Dimension of 2D channel. The Functon returns image sizes (w)x(h>>1)
 *
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */
void ScaleChannelDownX2Filter8_2Vertical(BYTE *in, BYTE *out, int w, int h)
{
	int i,j;
	int w_in = w, h_in = h, h_out = h_in>>1, w_out = w_in, h_end = h_out - 3;
	BYTE * pIn, *pOut;

	pIn = in;
	pOut = out;


	for(i = 0; i<w_in; i++)
	{
		pOut[i]=		CLIP_F(( 58* pIn[i       ] 
								+19* pIn[i+w_in  ] 
								- 9* pIn[i+w_in*2] 
								- 4* pIn[i+w_in*3] + 32)>>6 );
		
		pOut[i+w_out]=	CLIP_F(( 58*(pIn[i+w_in*2] + pIn[i+w_in  ])
								+19*(pIn[i+w_in*3] + pIn[i       ])
								- 9* pIn[i+w_in*4] 
								- 4* pIn[i+w_in*5] + 70)/141 );
	}
               
	pOut = out +w_out*2;

	for(j = 0; j<h_end; j++)
	{
		for(i=0; i<w_in; i++)
		{
		    pOut[i] = CLIP_F( ( 58*(pIn[i+w_in*4] + pIn[i+w_in*3]) 
							   +19*(pIn[i+w_in*5] + pIn[i+w_in*2])
							   - 9*(pIn[i+w_in*6] + pIn[i+w_in  ]) 
							   - 4*(pIn[i+w_in*7] + pIn[i       ]) +64)>>7 );
	    }
		pIn  += w_in*2;
		pOut += w_out;
	}

	for(i = 0; i<w_in; i++)
	{
	    pOut[i]=	  CLIP_F( ( 58*(pIn[i+w_in*3] + pIn[i+w_in*4]) 
							   +19*(pIn[i+w_in*2] + pIn[i+w_in*5]) 
							   - 9* pIn[i+w_in  ] 
							   - 4* pIn[i       ] + 70)/141 );
	}
}                                                                            

/*============================= ScaleChannelDownX2Filter8_2Horisontal ==============================*/
/**
 * Scale DOWN Horisontal Dimension of 2D channel. The Functon returns image sizes (w>>1)x(h)
 *
 * \param in          [IN]  - pointer to input one dimensional channels
 * \param out         [OUT] - pointer to output one dimensional channels
 * \param w           [IN]  - in-channel width 
 * \param h           [IN]  - in-channel height 
 * \retval - none
 */
void ScaleChannelDownX2Filter8_2Horisontal(BYTE *in, BYTE *out, int w, int h)
{
	int i,j;
	int w_in = w, h_in = h, h_out = h_in, w_out = w_in>>1, w_end = w_out - 3;
	BYTE * pIn, *pOut;

	for (j = 0; j<h_out; j++)
	{
		pIn = in + j*w_in;
		pOut = out + j*w_out;

		pOut[0]=		CLIP_F(( 58* pIn[0] 
								+19* pIn[1] 
								- 9* pIn[2] 
								- 4* pIn[3] + 32)>>6 );
		
		pOut[1]=		CLIP_F(( 58*(pIn[2] + pIn[1])
								+19*(pIn[3] + pIn[0])
								- 9* pIn[4] 
								- 4* pIn[5] + 70)/141 );
	                                                               
	pOut += 2;

		for(i=0; i<w_end;i++)
		{
	        pOut[i]=	CLIP_F(( 58*(pIn[3] + pIn[4]) 
								+19*(pIn[2] + pIn[5])
							    - 9*(pIn[1] + pIn[6]) 
						        - 4*(pIn[0] + pIn[7]) +64)>>7 );
			pIn+=2;
		}

	pOut += w_end;
	
	    pOut[0]=		CLIP_F(( 58*(pIn[3] + pIn[4]) 
							    +19*(pIn[2] + pIn[5]) 
							    - 9* pIn[1] 
							    - 4* pIn[0] + 70)/141 );
	}
}                                                                            


/************************  end of file **************************************/
